home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Gold Collection / Software Vault - The Gold Collection (American Databankers) (1993).ISO / cdr49 / 134_01.zip / CTOA.C < prev    next >
Text File  |  1993-06-12  |  20KB  |  905 lines

  1. /*    CTOA -- BDS `C' CRL-to-ASM postprocessor- part 1.    */
  2.  
  3. /*
  4.     Kevin B. Kenny
  5.     729-A E. Cochise Dr.
  6.     Phoenix, AZ   85020
  7. */
  8.  
  9. /*    Copyright (c) 1983 by Kevin B. Kenny
  10.     Released to the BDS `C' Users' Group for non-commercial distribution
  11.     only. */
  12.  
  13. /*    This program is a utility that generates assembly language (.CSM)
  14.     source files for BDS `C' programs.  It accepts the .CRL file for the
  15.     object instructions, the .CDB file for the symbols, and the .C source
  16.     file for commentary.  From these, it produces a .CSM file that generate
  17.     the same object code.
  18.  
  19.     Syntax:
  20.         ctoa source_file [>output_file]
  21. */
  22.  
  23. #include <bdscio.h>
  24. #include <dio.h>
  25. #include <cmdutil.h>
  26. #include "ctoatbls.h"
  27. #include "ctoa.h"
  28.  
  29. #define TITLE "CTOA version 83-11-11 copyright (c) 1983 by Kevin Kenny.\n"
  30.  
  31. /*    Main program    */
  32.  
  33. main (argc, argv)
  34.     int argc;
  35.     char * * argv;
  36.     {
  37.     /* Check command syntax */
  38.  
  39.     dioinit (&argc, argv);
  40.     if (argc != 2) {
  41.         fprintf (STD_ERR, "Usage: ctoa filename [>outfile]\n");
  42.         quit ();
  43.         }
  44.     fprintf (STD_ERR, TITLE);
  45.  
  46.     /* Pick up the source file name, and open the source */
  47.  
  48.     strcpy (srcfnam, argv [1]);
  49.     if (fopen (srcfnam, srcfile) == ERROR) {
  50.         fprintf (STD_ERR, "Can't open %s: %s\n", srcfnam, 
  51.                     errmsg (errno ()));
  52.         quit ();
  53.         }
  54.  
  55.     /* Acquire the opcode table */
  56.  
  57.     opc_tabl = opctabl ();
  58.  
  59.     /* Go get the .CRL  and .CDB files */
  60.  
  61.     initcdb ();
  62.     initcrl ();
  63.  
  64.     /* Process the content of the .CRL file */
  65.  
  66.     proccrl ();
  67.  
  68.     /* Flush any remaining text from the source file, and close it. */
  69.  
  70.     while (!seof) sscan ();
  71.     printf ("\n\n\tend\n");
  72.     fclose (srcfile);
  73.     if (cdbopen) cclose (cdbfile);
  74.  
  75.     /* Flush out directed I/O */
  76.  
  77.     dioflush ();
  78.  
  79.     }
  80.  
  81. /*    Set up processing of the .CRL file for object text     */
  82.  
  83. initcrl() {
  84.  
  85.     /* Get the .CRL file name */
  86.  
  87.     strcpy (crlfnam, srcfnam);
  88.     makeext (crlfnam, "CRL");
  89.  
  90.     /* Open the .CRL file, and read in the directory from it */
  91.  
  92.     tcopen (crlfile, crlfnam);
  93.     tcseek (crlfile, 0, CABS, crlfnam);
  94.     tcread (crlfile, crldir, sizeof crldir, crlfnam);
  95.  
  96.     /* Print a heading on the CSM file indicating the file name and
  97.        compilation options. */
  98.  
  99.     printf (";\t%s\tBDS `C' object code of %s\n", crlfnam, srcfnam);
  100.     printf (";\t\t\tCompilation options:");
  101.     if (havecdb) printf (" -k");
  102.     if (crldir.crleflag == 0xBD)
  103.         printf (" -e %04x", crldir.crleloc);
  104.     printf ("\n");
  105.     printf (";\t\t\tExternals use %d (0x%04x) bytes.\n", 
  106.             crldir.crlelen, crldir.crlelen);
  107.     printf ("\n\tMACLIB\t<BDS.LIB>\n\n");
  108.     if (crldir.crleflag == 0xBD)
  109.         printf ("SYS$EXTFLAG\tSET\t0BDH\nSYS$EXTADDR\tSET\t0%04xH\n",
  110.                                  crldir.crleloc);
  111.     printf ("SYS$EXTSIZE\tSET\t0%04xH\n\n", crldir.crlelen);
  112.  
  113.     /*    Print non-library-defined CCC symbols on the .CSM file. */
  114.  
  115.     initccc ();
  116.     }
  117.  
  118. /*    Process the functions on a .CRL file    */
  119.  
  120. proccrl () {
  121.     union {            /* .CRL directory pointer */
  122.         char * c;
  123.         int * i;
  124.         } dirp;
  125.  
  126.     /* Point dirp to the start of the directory */
  127.  
  128.     dirp.c = & (crldir.crldtext);
  129.  
  130.     /* Walk through the directory, doing functions one by one */
  131.  
  132.     for (;;) {
  133.         strcpy70 (fname, dirp.c);    /* Get function name */
  134.         if (!*fname) break;        /* Return if end of file */
  135.         dirp.c += strlen (fname);    /* Advance directory pointer */
  136.         faddr = *dirp.i++;        /* Get function address */
  137.         procfunc ();            /* Process the function */
  138.         }
  139.     cclose (crlfile);        /* All done; close file */
  140.     }
  141.  
  142. /*    Do one function from a .CRL file    */
  143.  
  144. procfunc () {
  145.  
  146.     /* Announce ourselves */
  147.  
  148.     fprintf (STD_ERR, "; Processing the %s function:\n", fname);
  149.  
  150.     /* Find the function on the source and .CDB files. */
  151.  
  152.     sfunct (fname);
  153.     cdbfunct (fname);
  154.  
  155.     /* Put the FUNCTION statement on the .CSM file */
  156.  
  157.     printf ("\n\tFUNCTION\t%s\n\n", fname);
  158.  
  159.     /* Process the external references from the function */
  160.  
  161.     procexts ();
  162.  
  163.     /* Output the stack frame layout */
  164.  
  165.     doframe ();
  166.  
  167.     /* Read in the function text and relocation */
  168.  
  169.     if (!readfunc ()) {
  170.         fprintf (STD_ERR, ";*** Function is too large to analyze.\n");
  171.         fprintf (STD_ERR, ";*** Break it up and try again.\n");
  172.         }
  173.  
  174.     else {
  175.         /* Construct the label table */
  176.  
  177.         bldlbtab ();
  178.  
  179.         /* Output the code */
  180.  
  181.         asmcode ();
  182.  
  183.         /* Get rid of allocated memory */
  184.  
  185.         freefunc ();
  186.         }
  187.  
  188.     /* Find the end of the function on the source */
  189.  
  190.     sendfn ();
  191.  
  192.     /* Put the ENDFUNC statement on the .CSM file */
  193.  
  194.     printf (";\n\tENDFUNC\t\t%s\n;\n", fname);
  195.     }
  196.  
  197. /*    Process the external reference directory from a function on the
  198.     .CRL file */
  199.  
  200. procexts () {
  201.     int extdlen;        /* Length of the external directory */
  202.     char syname [NAMLEN];    /* Name of an external symbol */
  203.     char * xnamp;        /* Pointer to current char in name */
  204.  
  205.     /* Position to the start of the function's external directory */
  206.  
  207.     extdlen = 0;
  208.     tcseek (crlfile, faddr, CABS, crlfnam);
  209.  
  210.     nexts = 0;        /* No externals yet. */
  211.  
  212.     /* Read externals from the file */
  213.  
  214.     for (;;) {
  215.         xnamp = & syname;
  216.         tcread (crlfile, xnamp, 1, crlfnam); ++extdlen;
  217.                     /* Get first byte of external name */
  218.         if (syname [0] == '\0') break;
  219.                     /* If it's zero, we're done. */
  220.         while ((*xnamp & 0x80) == 0) {
  221.             tcread (crlfile, ++xnamp, 1, crlfnam); ++extdlen;
  222.             }        /* Read the rest of the symbol */
  223.         *xnamp &= 0x7F;        /* Strip the 7th bit from last char */
  224.         *++xnamp = 0;        /* Add null terminator */
  225.         printf ("\tEXTERNAL\t%s\n", syname);
  226.                     /* Put EXTERNAL statement on .CSM */
  227.         strcpy (xname [nexts++], syname);
  228.                     /* Install name in table */
  229.         }
  230.     
  231.     /* End of external directory */
  232.  
  233.     printf (";\n");
  234.     ftaddr = faddr + extdlen + 2;    /* Find function text */
  235.     }    
  236.  
  237. /*    Read the text and relocation of a function    */
  238.  
  239. readfunc () {
  240.  
  241.     /* Read in the length word for the function text */
  242.  
  243.     tcseek (crlfile, ftaddr-2, CABS, crlfnam);
  244.     tcread (crlfile, &ftlen, 2, crlfnam);
  245.  
  246.     /* Get space for the function text, and read it in. */
  247.  
  248.     if ((ftext = alloc (ftlen)) == NULL) return (FALSE);
  249.     tcread (crlfile, ftext, ftlen, crlfnam);
  250.  
  251.     /* Read in the size of the relocation info */
  252.  
  253.     tcread (crlfile, &frlen, 2, crlfnam);
  254.  
  255.     /* Read in the relocation data itself */
  256.  
  257.     if ((freloc = alloc (2 * frlen)) == NULL) {
  258.         free (ftext);
  259.         return (FALSE);
  260.         }
  261.     tcread (crlfile, freloc, 2 * frlen, crlfnam);
  262.  
  263.     /* Tell the user what happened */
  264.  
  265.     fprintf (STD_ERR, ";\t%d (0x%04x) bytes of text, ", ftlen, ftlen);
  266.     fprintf (STD_ERR, "%d relocation directives,\n", frlen);
  267.     fprintf (STD_ERR, ";\t%d external functions", nexts);
  268.     if (havecdb) {
  269.      fprintf (STD_ERR, ", %d external variables,\n", nextvs);
  270.      fprintf (STD_ERR, ";\t%d auto variables, %d formal parameters, ",
  271.                   nautvs,        nparvs);
  272.      fprintf(STD_ERR, "frame size is %d (0x%04x)\n", framesize, framesize);
  273.      }
  274.     else fprintf (STD_ERR, "\n");
  275.     return (TRUE);
  276.     }
  277.  
  278. /*    Make the label table for a function    */
  279.  
  280. bldlbtab () {
  281.  
  282.     nlabs = 0;            /* Clear out the label table */
  283.  
  284.     pass1 = TRUE;            /* We're doing the label pass */
  285.  
  286.     dotext ();            /* Analyze text for line #s. */
  287.  
  288.     doreloc ();            /* Get other labels from relocation */
  289.  
  290.     }
  291.  
  292. /*    Make the assembly code for a function    */
  293.  
  294. asmcode () {
  295.     
  296.     pass1 = FALSE;            /* We're doing the code pass */
  297.  
  298.     dotext ();            /* Output the instructions */
  299.  
  300.     dospool ();            /* Output the string pool */
  301.     }
  302.  
  303. /*    Walk through the instructions for a function    */
  304.  
  305. dotext () {
  306.     char * label;            /* Label on the current word */
  307.     struct opc_entry * opcent;
  308.  
  309.     /* Set up the initial location counter past the external header */
  310.  
  311.     if (nexts == 0) locctr = 0;
  312.     else locctr = 3 * nexts + 3;
  313.     retaddr = ftlen;        /* Dummy up a return address */
  314.     highcode = 0;            /* Dummy up a high transfer address */
  315.  
  316.     /* Walk through the instruction sequence */
  317.  
  318.     while (locctr < retaddr) {
  319.  
  320.         /* Look up the opcode */
  321.  
  322.         opcode = ftext [locctr];
  323.         for (    opcent = opc_tabl;
  324.             (opcode & opcent -> opc_mask) != opcent -> opc_val;
  325.             ++opcent) ;
  326.  
  327.         /* In code pass, output the opcode, and any label that
  328.            may be needed. */
  329.  
  330.         if (!pass1) {
  331.             if ((label = findlab (locctr)) != NULL)
  332.                 printf ("\n%s:", label);
  333.             if (opcent -> opc_type != OP_RST6)
  334.                 printf ("\t%s", opcent -> opc_name);
  335.             }
  336.  
  337.         /* Process the opcode and flag the return address */
  338.  
  339.         switch (opcent -> opc_type) {
  340.               case OP_SIMPLE: dosimple (); break;
  341.             case OP_LXI:    dolxi ();    break;
  342.             case OP_RPSP:    dorpsp ();    break;
  343.             case OP_REG53:    doreg53 ();    break;
  344.             case OP_MVI:    domvi ();    break;
  345.             case OP_DATA1:    dodata1 ();    break;
  346.             case OP_DATA2:    dodata2 ();    break;
  347.             case OP_MOV:    domov ();    break;
  348.             case OP_ARITH:    doarith ();    break;
  349.             case OP_CONRET:    doconret ();    break;
  350.             case OP_RPPSW:    dorppsw ();    break;
  351.             case OP_CONTRA:    docontra ();    break;
  352.             case OP_TRANS:    dotrans ();    break;
  353.             case OP_IARITH:    doiarith ();    break;
  354.             case OP_RST:    dorst ();    break;
  355.             case OP_IO:    doio ();    break;
  356.             case OP_RST6:    dorst6 ();    break;
  357.             case OP_WHAT:    dowhat ();    break;
  358.             default:    
  359.                 fprintf (STD_ERR, "in dotext: can't happen\n");
  360.                 quit ();
  361.             }
  362.  
  363.         if (!pass1) printf ("\n");    /* End assembly line */
  364.         }
  365.     }
  366.  
  367. /*    *******    Processing routines for the various opcodes    ******* */
  368.  
  369. /*    Simple operations    */
  370.  
  371. dosimple () {
  372.     if (opcode == RET && locctr >= highcode) 
  373.         retaddr = locctr + 1;
  374.                 /* Set the return address from function */
  375.     ++locctr;
  376.     }
  377.  
  378. /*    LXI    */
  379.  
  380. dolxi () {
  381.     if (!pass1) {
  382.         tab ();                /* LXI x, addr */
  383.         do_pairsp ((opcode >> 4) & 0x03);
  384.         comma ();
  385.         do_imm2 ();
  386.         }
  387.     locctr += 3;
  388.     }
  389.  
  390. /*    Register pair (11 = SP)     */
  391.  
  392. dorpsp () {
  393.     if (!pass1) {
  394.         tab ();                /* INX x */
  395.         do_pairsp ((opcode >> 4) & 0x03);
  396.         }
  397.     ++locctr;
  398.     }
  399.  
  400. /*    Register number in bits 5-3    */
  401.  
  402. doreg53 () {
  403.     if (!pass1) {
  404.         tab ();                /* INR x */
  405.         do_regno ((opcode >> 3) & 0x07);
  406.         }
  407.     ++locctr;
  408.     }
  409.  
  410. /*    MVI    */
  411.  
  412. domvi () {
  413.     if (!pass1) {            
  414.         tab ();                /* MVI x, opd */
  415.         do_regno ((opcode >> 3) & 0x07);
  416.         comma ();
  417.         do_byte (ftext [locctr+1]);
  418.         }
  419.     locctr += 2;
  420.     }
  421.  
  422. /*    LHLD or SHLD    */
  423.  
  424. dodata2 () {
  425.     if (!pass1) {
  426.         tab ();                /* LHLD addr */
  427.         do_addr ();
  428.         }
  429.     locctr += 3;
  430.     }
  431.  
  432. /*    LDA or STA    */
  433.  
  434. dodata1 () {
  435.     if (!pass1) {
  436.         tab ();                /* LDA addr */
  437.         do_addr ();
  438.         }
  439.     locctr += 3;
  440.     }
  441.  
  442. /*    MOV    */
  443.  
  444. domov () {
  445.     if (!pass1) {
  446.         tab ();                /* MOV x, y */
  447.         do_regno ((opcode >> 3) & 0x07);
  448.         comma ();
  449.         do_regno (opcode & 0x07);
  450.         }
  451.     ++locctr;
  452.     }
  453.  
  454. /*    Arithmetic operations    */
  455.  
  456. doarith () {
  457.     if (!pass1) {
  458.         tab ();                /* ADD x */
  459.         do_regno (opcode & 0x07);
  460.         }
  461.     ++locctr;
  462.     }
  463.  
  464. /*    Conditional returns    */
  465.  
  466. doconret () {
  467.     if (!pass1) {    
  468.         do_ccode ();            /* Rcc */
  469.         }
  470.     ++locctr;
  471.     }
  472.  
  473. /*    Register pairs (11 = PSW)     */
  474.  
  475. dorppsw () {
  476.     if (!pass1) {
  477.         tab ();
  478.         do_pairpsw ((opcode >> 4) & 0x03);    /* PUSH xx */
  479.         }
  480.     ++locctr;
  481.     }
  482.  
  483. /*    Conditional transfers    */
  484.  
  485. docontra () {
  486.     if (!pass1) {
  487.         do_ccode ();            /* Jcc addr */
  488.         tab ();
  489.         }
  490.     do_xaddr ();
  491.     locctr += 3;
  492.     }
  493.  
  494. /*    Unconditional transfers    */
  495.  
  496. dotrans () {
  497.     struct ccc_entry * ccc;
  498.     if (!pass1) {
  499.         tab ();                /* JMP addr */
  500.         }
  501.     do_xaddr ();
  502.     if ((!isreloc (locctr+1))        /* Funny CCC operator? */
  503.      && (ccc = scanccc (textword (locctr+1), CCC_CODE))) {
  504.         if (!pass1) {
  505.             switch (ccc -> ccc_flags & 0x07) {
  506.                 case 1: printf ("\n\t     db\t");
  507.                     do_extoff (ftext [locctr+3]);
  508.                     break;
  509.                 case 2: printf ("\n\t     dw\t");
  510.                     do_extoff (textword (locctr+3));
  511.                     break;
  512.                 case 5: printf ("\n\t     db\t");
  513.                     do_autoff (ftext [locctr+3]);
  514.                     break;
  515.                 case 6: printf ("\n\t     dw\t");
  516.                     do_autoff (textword (locctr+3));
  517.                     break;
  518.                 }
  519.             }
  520.         locctr += ccc -> ccc_flags & 0x03;    /* Handle funny ops */
  521.         }
  522.     locctr += 3;
  523.     }
  524.  
  525. /*    Immediate arithmetic    */
  526.  
  527. doiarith () {
  528.     if (!pass1) {
  529.         tab ();                /* ADI xx */
  530.         do_byte (ftext [locctr+1]);
  531.         }
  532.     locctr += 2;
  533.     }
  534.  
  535. /*    Restarts other than 6    */
  536.  
  537. dorst () {
  538.     if (!pass1) {
  539.         tab ();                /* RST n */
  540.         printf ("%d", (opcode >> 3) & 0x07);
  541.         }
  542.     ++locctr;
  543.     }
  544.  
  545. /*    I/O operations    */
  546.  
  547. doio () {
  548.     if (!pass1) {
  549.         tab ();                /* IN 0nnH */
  550.         printf ("0%02xh", ftext [locctr+1]);
  551.         }
  552.     locctr += 2;
  553.     }
  554.  
  555. /*    Restart 6 (line number indication)     */
  556.  
  557. dorst6 () {
  558.  
  559.     char label[8];        /* Storage for labels in pass 1 */
  560.  
  561.     /*    If this is the label-making pass, assign a label to the
  562.         line for the disassembly pass to use.    */
  563.  
  564.     if (pass1) {
  565.         sprintf (label, "line%d", textword (locctr+1) & 0xFFF);
  566.         makelab (label, locctr);
  567.         }
  568.  
  569.     /* This is code pass.  Copy the source line to the .CSM file */
  570.  
  571.     else {
  572.         if (!(textword (locctr+1) & 0xF000)) {
  573.             printf ("\n");
  574.             slineno (textword (locctr+1) & 0xFFF);
  575.             }
  576.         }
  577.     locctr += 3;
  578.     }
  579.  
  580. /*    Unknown operation    */
  581.  
  582. dowhat () {
  583.     fprintf (STD_ERR, "; Warning: unknown opcode at location 0x%04x\n",
  584.                                 locctr);
  585.     fprintf (STD_ERR, ";\tHex value is %02x.\n");
  586.     if (!pass1) {
  587.         do_byte (opcode);
  588.         }
  589.     ++locctr;
  590.     }
  591.  
  592. /*    Put a register number on the .CSM file    */
  593.  
  594. do_regno (n)
  595.     int n;                /* Register number */
  596.     {
  597.     char * regnos;
  598.  
  599.     regnos = "bcdehlma";
  600.     printf ("%c", regnos [n]);
  601.     }
  602.  
  603. /*    Put a register pair (11=SP) on the .CSM file    */
  604.  
  605. do_pairsp (n)
  606.     int n;
  607.     {
  608.     switch (n) {
  609.         case 0:    printf ("b");    break;
  610.         case 1: printf ("d");    break;
  611.         case 2:    printf ("h");    break;
  612.         case 3: printf ("sp");    break;
  613.         }
  614.     }
  615.  
  616. /*    Put a register pair (11=PSW) on the .CSM file    */
  617.  
  618. do_pairpsw (n)
  619.     int n;
  620.     {
  621.     switch (n) {
  622.         case 0: printf ("b");    break;
  623.         case 1:    printf ("d");    break;
  624.         case 2: printf ("h");    break;
  625.         case 3:    printf ("psw");    break;
  626.         }
  627.     }
  628.  
  629. /*    Put a one-byte quantity on the .CSM file    */
  630.  
  631. do_byte (n)
  632.     char n;
  633.     {
  634.     printf ("0%02xh\t\t; %3d", n, n);
  635.     if (n >= ' ' && n <= '~')
  636.         printf (" ('%c')", n);
  637.     }
  638.  
  639. /*    Put a condition code on the .CSM file    */
  640.  
  641. do_ccode () {
  642.     switch (opcode >> 3 & 0x07) {
  643.         case 0:    printf ("nz");    break;
  644.         case 1: printf ("z");    break;
  645.         case 2:    printf ("nc");    break;
  646.         case 3:    printf ("c");    break;
  647.         case 4: printf ("po");    break;
  648.         case 5:    printf ("pe");    break;
  649.         case 6:    printf ("p");    break;
  650.         case 7:    printf ("m");    break;
  651.         }
  652.     }
  653.  
  654. /*    Put a two-byte immediate operand on the .CSM file    */
  655.  
  656. do_imm2 () {
  657.     if (ftext [locctr+3] == DADSP)
  658.         do_frsiz (textword (locctr+1));
  659.                 /* Appears to be a frame size */
  660.  
  661.     else if (ftext [locctr+3] == DADB)
  662.         do_autoff (textword (locctr+1));
  663.                 /* Appears to be an AUTO offset */
  664.  
  665.     else if (textword (locctr-2) == EXTRNS && ftext [locctr+3] == DADD)
  666.         do_extoff (textword (locctr+1));
  667.                 /* Appears to be an external variable offset */
  668.  
  669.     else            /* Don't know what it is */
  670.         do_laddr ();        /* Treat like address for now */
  671.     }
  672.  
  673. /*    Put a transfer address on the .CSM file            */
  674.  
  675. do_xaddr () {
  676.     struct ccc_entry * ccc;
  677.  
  678.     /* Remember highest transfer address so we can find the last RET */
  679.  
  680.     if (isreloc (locctr+1))    
  681.         if (textword (locctr+1) > highcode)
  682.             highcode = textword (locctr+1);
  683.     if (highcode > retaddr) retaddr = ftlen + 1;
  684.     if (pass1) return;
  685.  
  686.     /* Handle addresses in C.CCC */
  687.  
  688.     if (isreloc (locctr+1)
  689.      || !(ccc = scanccc (textword (locctr+1), CCC_CODE)))
  690.                 /* If not in C.CCC */
  691.         do_laddr ();    /* Treat like data address for now */
  692.     else
  693.         putccc (ccc);
  694.     }
  695.  
  696. /*    Put a data address on the .CSM file    */
  697.  
  698. do_addr () {
  699.     struct ccc_entry * ccc;
  700.  
  701.     if (isreloc (locctr+1)
  702.      || !(ccc = scanccc (textword (locctr+1), CCC_DATA)))
  703.                     /* If not in C.CCC ... */
  704.         do_laddr ();        /* treat as local for now */
  705.     else
  706.         putccc (ccc);
  707.     }
  708.  
  709. /*    Put a local address on the .CSM file    */
  710.  
  711. do_laddr () {
  712.     unsigned addr;        /* Address to print */
  713.  
  714.     addr = textword (locctr+1);    /* Get the address */
  715.  
  716.     if (isreloc (locctr+1)) {    /* Relative address? */
  717.         if (addr < 3 * nexts + 3) {    /* External? */
  718.             printf ("%s", xname [addr / 3 - 1]);
  719.             if (addr % 3) printf ("+%d", addr % 3);
  720.             }
  721.         else printf ("%s", findlab (addr));
  722.         }
  723.     else if (crldir.crleflag    /* Constant external address? */
  724.           && textword (locctr+1) >= crldir.crleloc
  725.           && textword (locctr+1) < crldir.crleloc + crldir.crlelen) {
  726.         printf ("SYS$EXTADDR+");
  727.         do_extoff (textword (locctr+1) - crldir.crleloc);
  728.         }
  729.     else  {
  730.         printf ("0%04xh\t\t; %d", addr);    /* Absolute address */
  731.         if (addr >= ' ' && addr <= '~')
  732.             printf (" ('%c')", addr);
  733.         }
  734.     }
  735.  
  736. /*    Print a tab     */
  737.  
  738. tab () {
  739.     printf ("\t");
  740.     }
  741.  
  742. /*    Print a comma    */
  743.  
  744. comma () {
  745.     printf (", ");
  746.     }
  747.  
  748. /*    Generate dummy labels for the targets of any relocated addresses */
  749.  
  750. doreloc () {
  751.     int xlabno;            /* Count of transfer points */
  752.     int strno;            /* Count of strings */
  753.     int i;                /* Loop index */
  754.     int addr;            /* Relocated target address */
  755.     char label [8];            /* Label to assign to it */
  756.  
  757.     xlabno = strno = 0;
  758.  
  759.     for (i=(nexts > 0); i<frlen; ++i) {    /* Walk the relocation list */
  760.         addr = textword (freloc [i]);    /* Get target address */
  761.         if (addr >= 3 * nexts + 3    /* Internal address? */
  762.          && findlab (addr) == NULL) {    /* Labeled yet? */
  763.             if (addr >= retaddr)    /* String pool? */
  764.                 sprintf (label, "str%d", ++strno);
  765.             else
  766.                 sprintf (label, "x%d", ++xlabno);
  767.             makelab (label, addr);
  768.             }
  769.         }
  770.     }
  771.  
  772. /*    Determine if a particular address is relocatable    */
  773.  
  774. int isreloc (offset)
  775.     unsigned offset;
  776.     {
  777.     int i;
  778.     for (i=frlen-1; i>=0; --i)
  779.         if (freloc [i] == offset) return (TRUE);
  780.     return (FALSE);
  781.     }
  782.  
  783. /*    Output the content of the string pool    */
  784.  
  785. dospool () {
  786.     
  787.     char spopen;            /* Flag: between quotes on DB */
  788.     char comma;            /* Flag: need comma on DB */
  789.     char * label;            /* Label to be printed */
  790.     char byte;            /* Byte we're working on */
  791.  
  792.     printf ("\n;\tString pool for function %s\n", fname);
  793.     spopen = comma = FALSE;        /* Haven't opened a quote yet */
  794.  
  795.     while ((locctr < ftlen) && (!findlab (locctr))) ++locctr;
  796.                     /* Skip any unreacahable epilogue */
  797.  
  798.     while (locctr < ftlen) {    /* Walk through string pool */
  799.         if (label = findlab (locctr)) {    /* Put out any labels */
  800.             if (spopen) {
  801.                 printf ("'");
  802.                 spopen = FALSE;
  803.                 }
  804.             comma = FALSE;
  805.             printf ("\n%s:\tdb\t", label);
  806.             }
  807.         
  808.         byte = ftext [locctr];    /* Get a byte from string */
  809.         if (byte < ' ' || byte > '~') {
  810.                     /* Printable? */
  811.             if (spopen) {        /* No; close out the string */
  812.                 printf ("'");
  813.                 spopen = FALSE;
  814.                 comma = TRUE;
  815.                 }
  816.             if (comma) {        /* Put out any needed comma */
  817.                 printf (", ");
  818.                 comma = FALSE;
  819.                 }
  820.             printf ("0%02xH", byte);    /* Put the byte */
  821.             comma = TRUE;        /* Need comma next time */
  822.             }
  823.  
  824.         else {
  825.             if (!spopen) {        /* Printable; open a quote */
  826.                 if (comma) {    /* First putting out comma */
  827.                     printf (", ");
  828.                     comma = FALSE;
  829.                     }
  830.                 printf ("'");
  831.                 spopen = TRUE;
  832.                 }
  833.             printf ("%c", byte);    /* add byte to quoted string */
  834.             if (byte == '\'') printf ("'");
  835.             }
  836.         ++locctr;    /* advance to next byte in pool */
  837.         }
  838.     if (spopen) printf ("'");
  839.     printf ("\n\n");
  840.     }
  841.  
  842. /*    Free the storage allocated for a function's text and relocation    */
  843.  
  844. freefunc () {
  845.  
  846.     free (freloc); freloc = NULL;
  847.     free (ftext); ftext = NULL;
  848.  
  849.     }
  850.  
  851. /*    Add a label to the list of relocatable labels    */
  852.  
  853. makelab (str, value)
  854.     char * str;                /* Name of the label */
  855.     unsigned value;            /* Relocation offset of the label */
  856.     {
  857.  
  858.     /* Never add a second label to a word */
  859.  
  860.     if (findlab (value) != NULL) return;
  861.  
  862.     /* Never define the same label twice */
  863.  
  864.     if (findaddr (str) != ERROR) return;
  865.  
  866.     /* Insert the new definition */
  867.  
  868.     lab_tab [nlabs] . lab_val = value;
  869.     strcpy (lab_tab [nlabs++] . lab_name, str);
  870.     }
  871.  
  872. /*    Find a label, by address, in the label list    */
  873.  
  874. char * findlab (value)
  875.     unsigned value;
  876.     {
  877.     int i;
  878.     for (i=nlabs-1; i>=0; --i)
  879.         if (lab_tab [i] . lab_val == value) 
  880.             return (&(lab_tab [i] . lab_name));
  881.     return (NULL);
  882.     }
  883.  
  884. /*    Find the address of a label, given its name    */
  885.  
  886. unsigned findaddr (str)
  887.     char * str;
  888.     {
  889.     int i;
  890.     for (i=nlabs-1; i>=0; --i)
  891.         if (!strcmp (lab_tab [i] . lab_name, str)) 
  892.             return (lab_tab [i] . lab_val);
  893.     return (ERROR);
  894.     }
  895.  
  896. /*    Extract a word from the function text    */
  897.  
  898. unsigned textword (offset)
  899.     unsigned offset;            /* Location of the word */
  900.     {
  901.     return ((ftext [offset+1] << 8) + ftext [offset]);
  902.     }
  903.  
  904. /*    Source continues in CTOA2.C    */
  905.   {